﻿using MessageBox;
using GeneralServices.ViewModel;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media.Imaging;
using WPF.MDI;

namespace GenericWin
{
    /// <summary>
    /// Application mère qui va contenir les menus de l'applicaton, ainsi que la zone MDI
    /// </summary>
    public partial class GenericApplication : Window
    {
        #region Attribut(s)

        /// <summary>
        /// Environnement
        /// </summary>
        private String environnement;

        /// <summary>
        /// Nom de l'application
        /// </summary>
        private String nomApplication;

        /// <summary>
        /// Numéro de version
        /// </summary>
        private String version;

        /// <summary>
        /// Booléan qui permet de savoir si on force la fermeture sans demander de message : Utiliser pour LogOff
        /// </summary>
        private bool forceClosing;

        #endregion

        #region Propriété(s)

        /// <summary>
        /// Observeur des actions sur les items du menu
        /// </summary>
        public IMenuAction Observer
        {
            get;
            set;
        }

        /// <summary>
        /// Envrionnement, si le setter est utilisé le titre de la fenetre est mise à jour
        /// </summary>
        public String Environnement
        {
            get
            {
                return environnement;
            }
            set
            {
                environnement = value;
                refreshTitle();
            }
        }

        /// <summary>
        /// Nom de l'application, si le setter est utilisé le titre de la fenetre est mise à jour
        /// </summary>
        public String NomApplication
        {
            get
            {
                return nomApplication;
            }
            set
            {
                nomApplication = value;
                refreshTitle();
            }
        }

        /// <summary>
        /// Numéro de version de l'application, si le setter est utilisé le titre de la fenetre est mise à jour
        /// </summary>
        public String Version
        {
            get
            {
                return version;
            }
            set
            {
                version = value;
                refreshTitle();
            }
        }

        /// <summary>
        /// Titre de la fenêtre, accès quand lecture
        /// </summary>
        public String Titre
        {
            get
            {
                return Environnement + " - " + NomApplication + " - [ Version " + Version + " ]";
            }
        }

        /// <summary>
        /// Instance de configuration comprenant tous les paramètres de l'application
        /// </summary>
        public Configuration Config
        {
            get;
            set;
        }

        #endregion

        #region Constructeur(s)

        /// <summary>
        /// Constructeur avec seul les menus en paramètre
        /// </summary>
        /// <param name="menu">Menu de la fenetre principale</param>
        public GenericApplication(List<MenuItemViewModel> menu)
        {
            InitializeComponent();
            GenericMenu ge = ((GenericMenu)MenuFenetre);
            ge.MakeMenu(menu);
            ge.GenericApplication = this;
        }

        /// <summary>
        /// Constructeur avec les menus en paramètre et l'observeur des actions sur le menu
        /// </summary>
        /// <param name="menu">Menu de la fenetre principale</param>
        /// <param name="action">Observeur, qui sera appelé si l'utilisateur clique sur un élément du menu pour savoir quel écran il faut afficher</param>
        public GenericApplication(List<MenuItemViewModel> menu, IMenuAction action)
            : this(menu)
        {
            Observer = action;
        }

        /// <summary>
        /// Constructeur avec seul l'observeur des actions sur le menu
        /// </summary>
        /// <param name="action">Observeur, qui sera appelé si l'utilisateur clique sur un élément du menu pour savoir quel écran il faut afficher</param>
        public GenericApplication(IMenuAction action)
        {
            InitializeComponent();
            Observer = action;
        }

        #endregion

        #region Méthode(s)

        /// <summary>
        /// Cette méthode est appelé si il y a un clic sur un élément du menu. 
        /// L'observeur est appelé, on construit ensuite la fenetre
        /// </summary>
        /// <param name="item">Item du menu cliqué</param>
        public void ActionMenu(MenuItemViewModel item)
        {
            // Ne pas ouvrir deux fois le même écran à partir du menu
            foreach (MdiChild m in Container.Children)
            {
                //if (m.Title.Equals(item.TitreEcran))
                //    return;
                if (m.ID.Equals(item.Id))
                    return;
            }

            GenericUserControl control = Observer.DoAction(item);
            if (control != null)
            {
                if (control.ExposeViewModel() != null)
                {
                    control.ExposeViewModel().ActionVM += OnActionLaunched;
                    control.ExposeViewModel().ActionVMClose += OnActionClosed;
                }

                MiseEnFormeControl(control);

                OpenWindow(control, item.Id, item.TitreEcran, true, item.ImageSource);
            }
        }


        private void OpenWindow(GenericUserControl control, String ID, String title, Boolean isMenu, Uri icon)
        {
            if (control != null)
            {
                MdiChild genericWindow = new MdiChild(ID);
                genericWindow.Content = control;
                // Icone du control
                genericWindow.ShowIcon = icon == null ? false : true;
                if(genericWindow.ShowIcon)
                    genericWindow.Icon = new BitmapImage(icon);

                //genericWindow.Position = new Point(posX, posY);

                if (isMenu)
                    genericWindow.Closing += genericWindow_Closing;

                // Si le user control est en plein écran, on réactulise le titre de l'application en le suffixant avec le titre du control en cours.
                genericWindow.SizeChanged += (s, e) =>
                {
                    if ((s as MdiChild) == this.Container.Current)
                    {
                        if ((s as MdiChild).WindowState == System.Windows.WindowState.Maximized)
                            refreshTitle(String.Format("{0} - {1}", Titre, (s as MdiChild).Title));
                        else
                            refreshTitle();
                    }
                };

                //posX += 15;
                //posY += 15;
                genericWindow.Title = title;
                Container.Children.Add(genericWindow);
            }
        }

        #region Evenements Ouverture / Fermeture Fenetres

        private void genericWindow_Closing(object sender, RoutedEventArgs e)
        {
            if (((sender as MdiChild).Content as GenericUserControl) != null &&
                ((sender as MdiChild).Content as GenericUserControl).ExposeViewModel() != null)
                ((sender as MdiChild).Content as GenericUserControl).ExposeViewModel().ActionVM -= OnActionLaunched;
        }

        private void OnActionLaunched(object sender, ActionVMArgs action)
        {
            if (action.Control is GenericUserControl && (action.Control as GenericUserControl).ExposeViewModel() != null)
                (action.Control as GenericUserControl).ExposeViewModel().ActionVM += OnActionLaunched;

            OpenWindow(action.Control as GenericUserControl, action.ID, action.Title, false, null);
        }

        private void OnActionClosed(object sender, ActionVMArgs action)
        {
            if (action.Control is GenericUserControl && (action.Control as GenericUserControl).ExposeViewModel() != null)
                (action.Control as GenericUserControl).ExposeViewModel().ActionVM -= OnActionLaunched;

            CloseWindow(action);
        }

        private void CloseWindow(ActionVMArgs action)
        {
            MdiChild mdi = null;

            if (action.Control != null)
                mdi = Container.Children.First(con => con.Content == action.Control);
            else if (action.ID != null)
                mdi = Container.Children.First(con => con.ID.Equals(action.ID));

            if (mdi != null)
            {
                mdi.Closing -= genericWindow_Closing;
                mdi.Close();
            }
        }

        #endregion

        /// <summary>
        /// 
        /// </summary>
        /// <param name="control"></param>
        private void MiseEnFormeControl(UserControl control)
        {
            //ColorConfiguration.MiseEnForme(control);
        }

        #endregion

        #region Evenements(s)

        /// <summary>
        /// Evenement lorsque l'utilisateur clique la croix de l'application
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void Window_Closing(object sender, System.ComponentModel.CancelEventArgs e)
        {
            if (!forceClosing)
            {
                // Fenetre de confirmation
                if (ShowMessageBox.Show(
                    TYPE_WINDOW_BOX.CONFIRM,
                    @"Vous allez quitter l'application. Toutes les modifications non enregistrées seront perdues.",
                    @"Souhaitez-vous quitter l'application ?") != TYPE_RESULT_BOX.OK)
                    e.Cancel = true;
            }
        }

        /// <summary>
        /// Méthode permettant de mettre à jour le titre de la fenetre
        /// Prend par défaut l'attribut Titre de l'instance.
        /// </summary>
        private void refreshTitle()
        {
            base.Title = Titre;
        }

        /// <summary>
        /// Méthode permettant de mettre à jour le titre de la fenetre
        /// <param name="newTitle">Nouveau titre de l'application</param>
        /// </summary>
        private void refreshTitle(String newTitle)
        {
            base.Title = newTitle;
        }

        /// <summary>
        /// Utiliser pour fermer l'application et réinstancié l'écran de connexion
        /// </summary>
        /// <param name="_forceClosing"></param>
        internal void LogOff(bool _forceClosing)
        {
            forceClosing = _forceClosing;
            this.Close();
        }

        #endregion
    }
}
